/*******************************
*  Hari Dasu Algorithm Implementation
*
*  Authors: Mark Anderson, Jeremy Goldin, Nathan Folkner
*
*  Contains function definitions
*
********************************/

#define MAX_INT 10000

#include "haridasu.h"
int name = 0;
int globalCount = 1;
int main()
{
	schedule  = fopen("schedules.txt", "w");
	vector<SWAT> solutions;
	vector<BB> CDFG;
	vector<S> allResSets;
	A thing;
	thing.prims[FF] = NUM_FF;
	thing.prims[BRAM] =  NUM_BRAM;
	thing.prims[LUT] = NUM_LUT;
	thing.prims[DSP] = NUM_DSP;

	/*Currently 1, 4, and 6 work*/
	//executeHariDasu(TEST1, thing);
	//executeHariDasu(TEST3, thing);
	//executeHariDasu(TEST4, thing); //This needs to change FF to 10000
	//executeHariDasu(TEST5, thing);//doesn't work has a node with 3 sucessors
	executeHariDasu(TEST6, thing);
	//executeHariDasu(TEST7, thing);
	printf("|||||||||||||||||||||||||||||||||||||||||\n");
}

/*************************
* WSDP()
*
* Relative Area Cost
*
* Inputs:
*        A kSubI       - the primitives used by the implmentation
*        A aSubI       - available primitives
*
* Outputs: 
*        float weight
*************************/

void resetAV()
{
	for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
	{
		(*it)->scheduled = (*it)->ready = (*it)->timeFrameMax = (*it)->timeFrameMin = (int)0;
		(*it)->prob = 0;
		(*it)->timestep = 1;
	}
}


float WSDP(A kSubI, A aSubI)
{
	float weight=0;
	/* for every primitive type... */
	for(int i = 0; i < NUM_PRIM; i++)
	{
		/* accumulate prims_needed / prims_available */ 
		weight += (float)kSubI.prims[i] / (float)aSubI.prims[i];
	}
	return weight;
}

/**************************
* calcTmin()
*
* Inputs: a vector of BBs
*
* Outputs: int result
**************************/
int calcTmin(vector<BB> graph)
{
	float sum = 0;

	for(vector<BB>::iterator it = graph.begin(); it != graph.end(); it++)
	{
		sum += static_cast<float>((*it).minLatency) * (*it).prob * static_cast<float>((*it).numIt);
	}
	return (int)ceil(sum);
}

/*************************
* calcT() - returns the adjusted T that reflects BB's current latency.
*           It does this by adding Fi * Ni * (Tnew - Tmin) to Tin
* 
* Inputs: 
*         Tin - the base T
*         BB  - the BB we are modifying
* Outputs: 
*         an integer with the adjusted T
***************************/
int calcT(int Tin, BB basicBlock)
{
	return (int)(Tin + basicBlock.prob * basicBlock.numIt * (basicBlock.curLatency - basicBlock.minLatency));
}

/*************************
*  Evaluate()
*
*   Returns a set of partial solutions given a particular BB, the resSets of that BB, and
*   the current SWAT solution.  
*
* Inputs:
*         (type?) DFG        - the data flow graph being evaluated
*         vector <R> resSets - the resource sets of DFG
*         SWAT curSolution   - the current solution
* Outputs:
*         vector <SWAT> X - set of partial solutions
*
*************************/
void evaluate(BB* basicBlock, vector<S>* resSets, SWAT* inSWAT, vector<SWAT>* X)
{
	SWAT localSWAT;
	float wPrime;
	float wTemp;
	int chosenImp;
	/* 1. X <- Empty solution set */
	//vector<SWAT> X;   //the set of partial solutions

	/* 2. For each resource set of G, do... */
	for(vector<S>::iterator it = resSets->begin(); it != resSets->end(); it++)
	{

		for(int i =0; i< NUM_RES; i++)
			for(int j = 0; j < MAX_IMPL; j++)
				if((*it).resImpl[i][j])
					(*it).resImpl[i][j]=0;

		/* a. W <- Win, A <- Ain */
		localSWAT.weight = inSWAT->weight;
		localSWAT.availPrims = inSWAT->availPrims;    //TODO: will this actually transfer the correct values? I doubt it

		//a little code for tracking the latency of each BB
		for(int i = 0; i< MAX_BB; i++)
			localSWAT.BB_Latency[i] = inSWAT->BB_Latency[i];

		/* For each type of resource in R do... */
		for( int resTypeCount=0; resTypeCount < NUM_RES; resTypeCount++)
		{
		
			/*If the res we need is greater than what we've already allocated */
			if( (*it).resCount[resTypeCount] > inSWAT->setRes.resCount[resTypeCount])
			{
				int extraRes = (*it).resCount[resTypeCount] - inSWAT->setRes.resCount[resTypeCount];

				/* For every extra resource we need to add to our solution...*/
				for(int i = 0; i < extraRes; i++)
				{

					/* i) For the available device prims (A),  recompute WSDPs of all implementations of the
					* resource r and select the least one wPrime.  If any two implementations have the
					* same WSDP, then select the implementation with the least standard deviation. */
					wPrime = std::numeric_limits<float>::max(); //init wPrime to max possible float
					chosenImp = 0;

					/* for every possible implementation of resType...*/
					for(int impCount = 0; impCount < resTypes[resTypeCount].numImp; impCount++)
					{
						wTemp = WSDP(resTypes[resTypeCount].resImp[impCount], localSWAT.availPrims);
						if(wTemp < wPrime)
						{
							wPrime = wTemp;    //keep only the lowest weight value
							chosenImp = impCount;
						}
					}
					it->resImpl[resTypeCount][chosenImp]++;

					/* ii) W <- W + wPrime */
					localSWAT.weight += wPrime;

					/* iii) Update available device primitives (A) by subtracting from A, the number of device 
					* primitives required by the implementation of resource r. */
					localSWAT.availPrims -= resTypes[resTypeCount].resImp[chosenImp];

				} //end loop
			}//end if
		} // end for every res type

		/* c.  Calculate the exectution time (T) of the CDFG, using latency j for the current DFG */
		basicBlock->curLatency = (*it).latency;  // set the BB's curLatency to the resSet's latency
		localSWAT.time = calcT(inSWAT->time, (*basicBlock));
 		localSWAT.BB_Latency[basicBlock->name] = basicBlock->curLatency;

		/* d. If the number of available device primitives (A) is non-negative, add the current solution
		*     (Sj, W, A, T) to the solution set X */
		localSWAT.setRes =  (*it) + inSWAT->setRes;

		if(!localSWAT.availPrims.lessThanZero())
		{
			X->push_back(localSWAT);
		}
	}
	//return X;
}

/*********************
* findResSets()
* 
* Given a BB with a min latency value, find and return all sets of 
* resources using FDS and incrementing the latency until there's one or less of each resource
**********************/
vector<S> findResSets(BB bbi)
{
	S resSet;
	int latency = bbi.minLatency;
	vector<S> allResSets;
	
	do
	{
		if(FDS(&bbi.allVertices,latency, &resSet, stdout, 1))
		{
			resSet.latency = latency++;
			allResSets.push_back(resSet);
		}

	}while(!resSet.minSet());
	//printf("YAY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n");
	return(allResSets);
}

/***********************
* ParetoOptimal()
*
* BB_count is the number of BBs that need to be present.
* Without this, it would always weed out the solutions that had two BBs present since
* they require more resources.
*
* Given a set of SWAT solutions, weed out the shitty ones.  Removes them from the given vector.
* Since erasing an element of the vector using an iterator causes the iterator to become invalid,
* we must break from the loop(s) every time we find a swap to do.  This makes this algorithm
* very inefficient at O(n^3), but meh, whatever.
***********************/
void paretoOptimal(vector<SWAT>* in, int BB_count)
{
	bool foundNonOptimal = true;

	while(foundNonOptimal)
	{
		foundNonOptimal = false;
		for(vector<SWAT>::iterator it = in->begin(); it != in->end(); it++)
		{
			for(vector<SWAT>::iterator it2 = (it+1); it2 != in->end(); it2++)
			{
				if((*it).BB_Latency[BB_count] == -1)
				{
					in->erase(it);
					foundNonOptimal = true;
					break;     //break out of inner 'for' loop
				}
				else if((*it2).BB_Latency[BB_count] == -1)
				{
					in->erase(it);
					foundNonOptimal = true;
					break;     //break out of inner 'for' loop
				}
				//if the current solution is better than another, throw that one out.
				// OR if the other one doesn't have as many BBs in it...
				else if(( (*it2).weight >= (*it).weight && (*it2).time >= (*it).time ))
				{
					//printf("erasing W = %f, T=%d because it's worse than W=%f, T=%d\n", (*it2).weight, (*it2).time, (*it).weight, (*it).time);
					in->erase(it2);
					foundNonOptimal = true;
					break;  //break out of inner 'for' loop
				}
				
				//if the current solution is worse than any others throw this one out
				// OR if this one doesn't have as many BBs in it...
				else if( ((*it).weight >= (*it2).weight && (*it).time >= (*it2).time))
				{
					//printf("erasing W = %f, T=%d because it's worse than W=%f, T=%d\n", (*it).weight, (*it).time, (*it2).weight, (*it2).time);
					in->erase(it);    //erasing the iterator makes the iterator invalid for future use...start over.
					foundNonOptimal = true;
					break;     //break out of inner 'for' loop
				}
			}
			if(foundNonOptimal)
				break;       //break out of outer 'for' loop
		}
	}
	return;  // we made it through without erasing anything
}

/***********************
*
* The actual algorithm.  It needs a complete CDFG to be passed to it,
* which includes the calculated minLatency for each BB, and much, much more.
*
***********************/
void executeHariDasu(char * cdfgFileName, A initialAvailPrims)
{
	int BB_count = 0;
	vector<SWAT> pCurrent;
	vector<SWAT> xNew;
	vector<SWAT> xM;
	vector<SWAT> xOptimal;
	vector<S> allResSets;
	/* 1. Determine CP(Gi) for every BB */
	CDFG = CDFGMaker(CDFG, cdfgFileName);	//takes in the filename of the CDFG file we want to check and creates a vector of BBs with the appropriate variables updated (CP, prob, etc)

	/*
	CDFG needs:
		for each cdfg we need a weights and lengths
		fix min cp
	*/
	/* 2. Calculate Tmin */
	int tMin = calcTmin(CDFG);
	
	/* 3. Create empty solution SWAT */
	SWAT solution;
	solution.availPrims = initialAvailPrims; 
	solution.time = tMin;

	/* 4. Using FDS find all schedules and resource sets of G1 */
	BB bb1 = CDFG.front();      // I'm a^ssuming bb1 is on front of vertex 
	allResSets = findResSets(bb1);	//This is FDS
	
	/*5. For all resSets, evaluate() and generate a set of partial solutions pCurrent */
	evaluate(&bb1, &allResSets, &solution, &pCurrent);
	
	/* 6. If pCurrent is empty set, terminate algorithm */
	if(pCurrent.empty())
	{
		printf("returning because pCurrent is empty\n");
		return;
	}
	

	/* 7.  For BBs 2...nDFG */
	if(CDFG.size() >=2)
	{
		for(vector<BB>::iterator itBB = CDFG.begin()+1; itBB != CDFG.end(); itBB++)
		{
			//increment the count of BB we're currently working on
			BB_count++;

			/* a. Using FDS, find all schedules of BBi */
			allResSets = findResSets(*itBB);

			/* b. Xnew <- Empty solution set */
			xNew.clear();

			/* c. For a solution (*itSWAT) in the set Pcurrent, do... */
			for(vector<SWAT>::iterator itSWAT = pCurrent.begin(); itSWAT != pCurrent.end(); itSWAT++)
			{
				/* i. For all resource sets obtained in step 7a, evaluate BBi and
				*     generate a set of partial solutions Xm */
				evaluate(&(*itBB), &allResSets, &(*itSWAT), &xM);

				/* II. Append solutions in set Xm to Xnew */
				while(!xM.empty())
				{
					xNew.push_back(xM.back());
					xM.pop_back();
				}
			}

			/* d. If xNew is an empty set, the algorithm is terminated */
			if(xNew.empty())
			{
				printf("xNew was empty...terminating algorithm\n");
				return;
			}

			/* e. Retain set of partial Pareto optimal solutions PCurrent from set xNew */
			//   append xNew onto pCurrent and then weed out non-optimal solutions from pCurrent
			while(!xNew.empty())
			{
				pCurrent.push_back(xNew.back());
				xNew.pop_back();
			}
			paretoOptimal(&pCurrent, BB_count);   
		}
	}
	
	/* 8. Calculate Wmux and Wreg using a mapping algorithm for each solution in the Pareto optimal solution,
	*     Pcurrent, and add them to the WSDP of each solution, resulting in a new set pPrimeCurrent. */
	float Wmux, Wreg;
	S * tempasdf = (S *)malloc(sizeof(S));
	FILE * file1 = fopen("ugly.txt", "w");
	for(vector<SWAT>::iterator itSWAT = pCurrent.begin(); itSWAT != pCurrent.end(); itSWAT++)
	{
		for(vector<BB>::iterator bb = CDFG.begin(); bb != CDFG.end(); bb++)
			FDS(&(*bb).allVertices, (*itSWAT).BB_Latency[(*bb).name], tempasdf, file1, 0);

		mapping(&(*itSWAT), &Wmux, &Wreg);
		(*itSWAT).weight += (Wmux + Wreg);
		printf("Wmux = %f, Wreg = %f\n", Wmux, Wreg);
		//resetAV();
	}

	/* 9. Retain Pareto optimal solutions from pPrimeCurrent resulting in a new set pFinal */
	paretoOptimal(&pCurrent, BB_count);
	
	/* 10. The final set of Pareto optimal solutions Pfinal along with their corresponding schedules
	*      represents the set of context adaptable architectures. */
	printSWATS(&pCurrent);
}


#define INST_MAX 30
#define TIME 400
/* Given a schedule and resSet, map an operation to a specific resource at each clock cycle */
void mapping(SWAT* inSWAT, float* Wmux, float* Wreg)
{
	/* reservation table - holds associations of data nodes present in the DFG to the hardware resources */
	int resTable [TIME][NUMBER_OF_RESOURCE_TYPES][INST_MAX];

	/* track the total bindings to a particular resource over all time */
	int resTotal[NUMBER_OF_RESOURCE_TYPES][INST_MAX];

	//initialize res_table to zeros
	for(int i = 0; i < TIME; i++)
	{	
		for(int j = 0; j < NUMBER_OF_RESOURCE_TYPES; j++)
		{
			for(int k = 0; k < INST_MAX; k++)
			{
				resTotal[j][k] = 0;
				resTable[i][j][k] = 0;
			}
		}
	}

	/*for every DFG in the CDFG... */
	for(vector<BB>::iterator DFG = CDFG.begin(); DFG != CDFG.end(); DFG++)
	{
		/* go from earliest clock cycle to latest */
		for ( int clk = 1; clk < inSWAT->BB_Latency[DFG->name]; clk++)
		{

			/* for every resource type ... */
			for(int resType = 0; resType < NUMBER_OF_RESOURCE_TYPES; resType++)
			{
				/* for every operation to be executed this clk cycle... */
				for(list<vertex *>::iterator node = DFG->allVertices.begin(); node != DFG->allVertices.end(); node++)
				{
					if((*node)->timestep == clk && (*node)->type == resType)
					{
				
					/* When a node is mapped to a specific resource, the
					*  mappings of its parents' nodes are compared with the
					*  mappings of the parent nodes of the nodes mapped to
					*  the current resource */ 
					
					/* If a match is found, then the current node is mapped
					* to the current resource */
					if(findBusMatches())
					{
						//go ahead and map the current node to this resource
						resTable[clk][resType][match_found]++;
						resTotal[resType][match_found]++;
					}
					
					/* If a match is not found, the current node is mapped to
					*  a resource with the least number of node mappings */
					else
					{
						int leastVal = MAX_INT;
						int leastInd = 0;
						//this does least number of node mappings EVER for a particular res
						for(int i = 0; i < inSWAT->setRes.resCount[resType]; i++)
						{

							if(resTotal[resType][i] < leastVal && resTable[clk][resType][i] == 0)
							{
								leastVal = resTotal[resType][i];
								leastInd = i;
							}
						}
						//bind the operation to the resource
						resTable[clk][resType][leastInd]++;
						resTotal[resType][leastInd]++;
					}
				} // for every operation to be executed
			} // for every resource type
		}

		//reset resTable
		for(int i = 0; i < NUMBER_OF_RESOURCE_TYPES; i++)
			for(int j=0; j < INST_MAX; j++)
				for(int k=0; k<INST_MAX;k++)
					resTable[i][j][k] = 0;
		} //for every clk cycle in the BB
	}// for every DFG in the CDFG

	/* after the reservation table is complete for this DFG, update
	* the port lists.
	*
	* Every resource has a port list associated with it.  The port list
	* is populated with only distinct node and/or register mappings.  The
	* number of entries tells us how large the mux is on that resource */
	int portList[NUMBER_OF_RESOURCE_TYPES][INST_MAX];
	for(int i = 0; i < NUMBER_OF_RESOURCE_TYPES; i++)
		for(int j=0; j < INST_MAX; j++)
			portList[i][j]= resTotal[i][j];
	 
	const int dataWidth = 32;
	int numLutMux = 0;
	for(int i = 0; i < NUMBER_OF_RESOURCE_TYPES; i++)
	{
		for(int j=0; j < INST_MAX; j++)
		{
			numLutMux += estimateLUTMUX(portList[i][j], dataWidth);
		}
	}

	int count = 0;
	/*for every DFG in the CDFG... */

	for(vector<BB>::iterator DFG = CDFG.begin(); DFG != CDFG.end(); DFG++)
	{
		for(list<vertex *>::iterator it = DFG->allVertices.begin(); it != DFG->allVertices.end(); it++)
		{
			count+=delayRegCount((*it), (*DFG));
		}
	}

		int numLutDReg = count*ceil(delay_cycles/16.0) * dataWidth;
		int numFFDReg = count*ceil(delay_cycles/64.0) * dataWidth;

	A muxesRegs;
/* Now we know how many LUTS and FFs the muxes and delay registers
*  are using and can now use WSDP to calculate Wmux and Wreg */
	muxesRegs.prims[LUT] = numLutMux;
	*Wmux = WSDP(muxesRegs, inSWAT->availPrims);
	inSWAT->availPrims -= muxesRegs;

	muxesRegs.prims[LUT] = numLutDReg;
	muxesRegs.prims[FF] = numFFDReg;
	*Wreg = WSDP(muxesRegs, inSWAT->availPrims);
	inSWAT->availPrims -= muxesRegs;
}

int delayRegCount(vertex *node, BB DFG)
{
	int count= 0;
	if(node->sucessors[0] != -1 || node->sucessors[1] != -1)
		for(list<vertex *>::iterator it = DFG.allVertices.begin(); it != DFG.allVertices.end(); it++)
			if((*it)->vertexNum == node->sucessors[0] ||(*it)->vertexNum == node->sucessors[1])
				count += ((*it)->timestep - node->timestep > 1)?1:0;
	return count;
}

/*  Number of inputs (n)
*   dataWidth
*
* returns the number of LUTs needed to implement
* the mux with n inputs */
int estimateLUTMUX(int n, int dataWidth)
{
	int p;
	int L; 
	if(n <= 1)
		return 0;
	else
	{
		p = n + ceil( log((float)n)/log(2.0) );
		L = 0;
		while(p/4 != 0)
		{
			L = L + p/4;
			p = p/4 + p%4;
		}
		
		if(p > 1)
			L++;
	}
	return(L * dataWidth);
}
/*********************************
* printSWATS()
*
* prints a vector of swats to the file solutions.txt
*
* input   - a vector of SWAT solutions
* returns - 0 if successful
*           1 if unsuccessful
************************************/

int printSWATS(vector<SWAT>* in)
{
	int imp_count = 0;
	FILE * fp, *file;
	fp = fopen("solutions.txt", "w");
	file = fopen("schedules.txt", "w");
	S * tempasdf = (S *)malloc(sizeof(S));
	if (fp == NULL)
    {
		// Open failed - take error handling action.
		printf("Failed to open solutions.txt for write\n");
		return 1;
    }
	for(vector<SWAT>::iterator it = in->begin(); it != in->end(); it++)
	{
			fprintf(fp, "\n*****************");
			//S
			fprintf(fp, "S (resource set): \n");
			for(int i = 0; i < NUM_RES; i++)
			{
				fprintf(fp, "\t%-7s: ", resNames[i]);
				fprintf(fp, "\t%i", it->setRes.resCount[i]);
				for(int j=0; j<MAX_IMPL; j++)
				{
					fprintf(fp, "\tIMP%i: ", j);
					if(it->setRes.resImpl[i][j] > 0)
					{
						fprintf(fp, "%i\t", it->setRes.resImpl[i][j]);
					}
					else
						fprintf(fp, " \t");
				}
				fprintf(fp, "\n");
			
				//currently the implementation chosen by Evaluate() isn't stored anywhere...
			}
			
			//W
			fprintf(fp, "\nW (weight): \n");
			fprintf(fp, "     %f\n", it->weight);
			
			//A
			float temp = 0;
			fprintf(fp, "\nA (available primitives) \t\t(used primitives)\n");
			for(int i = 0 ; i < NUM_PRIM; i++)
			{
				fprintf(fp, "     %s: ", primNames[i]);
				fprintf(fp, "%i\t\t\t\t\t", it->availPrims.prims[i]);
				fprintf(fp, "     %s: ", primNames[i]);
				switch(i)
				{
					case 0: fprintf(fp, "%i\n", NUM_BRAM - it->availPrims.prims[i]);
							temp += NUM_BRAM - it->availPrims.prims[i];
						break;
					case 1: fprintf(fp, "%i\n", NUM_FF - it->availPrims.prims[i]);
							temp += NUM_FF - it->availPrims.prims[i];
						break;
					case 2: fprintf(fp, "%i\n", NUM_LUT - it->availPrims.prims[i]);
							temp += NUM_LUT - it->availPrims.prims[i];
						break;
					case 3: fprintf(fp, "%i\n", NUM_DSP - it->availPrims.prims[i]);
							temp += NUM_DSP - it->availPrims.prims[i];
						break;
				}
			}
			float util = NUM_BRAM +NUM_FF+NUM_LUT+NUM_DSP;
			float num = temp/util;
			fprintf(fp, "\t\tUtilization : %2.2f%%\n", num*100);
			
			//T
			fprintf(fp, "\nT (latency): \n");
			fprintf(fp, "     %i\n", it->time);	

			fprintf(file, "SWAT #%i\n", imp_count);
			/* for each basic block... */
			globalCount = 1;
			for(int i = 0; i < MAX_BB; i++)
			{	
				//if there's such a BB...
				if((*it).BB_Latency[i] > 0)
				{
					fprintf(file, "BB %i:\t\tNum Iterations: %i\t\tProbability: %.2f\n", i, CDFG.at(i).numIt, CDFG.at(i).prob);
					//print the schedule
					FDS(&CDFG.at(i).allVertices, (*it).BB_Latency[i], tempasdf, file, 1);
				}
			
			}
			fprintf(file, "---------------------------\n");
			imp_count++;
	}
	fclose(file);
	fclose(fp);
	return 0;
}



int printSWAT(SWAT in)
{

			//S
			printf("S (resource set): \n");
			for(int i = 0; i < NUM_RES; i++)
			{
				printf("     %s: ", resNames[i]);
				printf("%i\n", in.setRes.resCount[i]);
			
				//currently the implementation chosen by Evaluate() isn't stored anywhere...
			}
			
			//W
			printf("\nW (weight): \n");
			printf("     %f\n", in.weight);
			
			//A
			printf("\nA (available primitives): \n");
			for(int i = 0 ; i < NUM_PRIM; i++)
			{
				printf("     %s: ", primNames[i]);
				printf("%i\n", in.availPrims.prims[i]);
			}

			
			//T
			printf("\nT (latency): \n");
			printf("     %i\n", in.time);	
	return 0;
}



vector<BB> CDFGMaker(vector<BB> CDFG, char* CDFGname)	//takes in the name of the file to get the CDFG info from
{
	//vector<BB> CDFG;
	FILE* file = fopen(CDFGname, "r");
	//int numVertices;
	if(file == NULL)
		printf("CDFGMaker: no such file\n");
	vertex tempArray[100];	// <-- make into a list or just big enough?
	char word[100];
	int count = 0;
	fscanf(file, "%s", word);//reading "FUNCTION"
	fscanf(file, "%s", word);//reading "main"
	while (!feof(file))	//while !all BBs read
	{
		count++;
		BB tempBB;
		if(strcmp(word, "BASIC_BLOCK"))
			fscanf(file, "%s", word);//reading "BASIC_BLOCK"
		fscanf(file, "%d", &tempBB.name);
		//printf("\n-----%s %d-------\n", word, tempBB.name);		
		fscanf(file, "%s", word);//reading "NumIt"
		fscanf(file, "%d", &tempBB.numIt);
		fscanf(file, "%s", word);//reading "Prob"
		fscanf(file, "%f", &tempBB.prob);
		//next words are BASIC_BLOCK # - just need the number for the name of the BB
		//read in the BB name/number  <---- update the BB struct to have this

		//have probability and iterations afterwards?
		//next words in file are in format: DATA_NODE # Operation - create the vertex for each node to be updated with further information later
		fscanf(file, "%s ", word);
		while (!strcmp(word,"DATA_NODE")) 
		{
			vertex * temp = (vertex *)malloc(sizeof(vertex));
			temp->scheduled = temp->ready = temp->timeFrameMax = temp->timeFrameMin = 0;
			temp->prob = 0;
			temp->timestep = 1;
			temp->predecesors[0] = temp->predecesors[1] = temp->sucessors[0] = temp->sucessors[1] = -1;
			fscanf(file, "%d", &temp->vertexNum);
			fscanf(file, "%s", word);
			if(!strcmp(word, "IADD")) 
				temp->type = IADD_TYPE;
			else if(!strcmp(word, "FADD"))
				temp->type = FADD_TYPE;
			else if(!strcmp(word, "ISUB"))
				temp->type = ISUB_TYPE;
			else if(!strcmp(word, "FSUB"))
				temp->type = FSUB_TYPE;
			else if(!strcmp(word, "IMUL"))
				temp->type = IMULT_TYPE;
			else if(!strcmp(word, "FMUL"))
				temp->type = FMULT_TYPE;
			else if(!strcmp(word, "RIGHT_SHIFT"))
				temp->type = RIGHT_SHIFT_TYPE;
			else if(!strcmp(word, "LEFT_SHIFT"))
				temp->type = LEFT_SHIFT_TYPE;
			else if(!strcmp(word, "LOAD"))
				temp->type = LOAD_TYPE;
			else if(!strcmp(word, "STORE"))
				temp->type = STORE_TYPE;
			else if(!strcmp(word, "IDIV"))
				temp->type = IDIV_TYPE;
			else if(!strcmp(word, "FDIV"))
				temp->type = FDIV_TYPE;
			else if(!strcmp(word, "CMP"))
				temp->type = CMP_TYPE;
			else if(!strcmp(word, "FABS"))
				temp->type = FABS_TYPE;
			else if(!strcmp(word, "FSQR"))
				temp->type = FSQR_TYPE;
			else if(!strcmp(word, "IABS"))
				temp->type = IABS_TYPE;
			else if(!strcmp(word, "IAND") || !strcmp(word, "AND"))
				temp->type = IAND_TYPE;
			fscanf(file, "%s ", word);
			tempBB.allVertices.push_back(temp);
		}
		while (!strcmp(word,"DATA_CON"))
		{
			int pred, succ;
			char waste;
			fscanf(file, "%d %d %c %c", &pred, &succ, &waste, &waste);
			for(list<vertex*>::iterator it= tempBB.allVertices.begin(); it != tempBB.allVertices.end(); it++)
			{
				if((*it)->vertexNum == pred)
				{
					if((*it)->sucessors[0] == -1)
						(*it)->sucessors[0] = succ;
					else 
						(*it)->sucessors[1] = succ;
				}
				else if((*it)->vertexNum == succ)
					if((*it)->predecesors[0] == -1)
						(*it)->predecesors[0] = pred;
					else 
						(*it)->predecesors[1] = pred;
			}
			fscanf(file, "%s ", word);
		}
		#ifdef FDS_DEBUG
		for(list<vertex*>::iterator it= tempBB.allVertices.begin(); it != tempBB.allVertices.end(); it++)
			printf("%d:\t%d\t%d\t%d\t%d\t%d\n", (*it)->vertexNum, (*it)->type, (*it)->sucessors[0], (*it)->sucessors[1], (*it)->predecesors[0], (*it)->predecesors[1]);
		#endif
		//read in the BB min latency (CP)
		CDFG.push_back(tempBB);
		if(!strcmp(word,"END_FUNCTION"))
			break;
		
	/*	for(vector<BB>::iterator BBit = CDFG.begin(); BBit != CDFG.end(); BBit++)
			for(list<vertex*>::iterator it= (*BBit).allVertices.begin(); it != (*BBit).allVertices.end(); it++)
				printf("\t%d:\t%d\t%d\t%d\n", (*it)->vertexNum, (*it)->type, (*it)->sucessors[0], (*it)->sucessors[1], (*it)->predecesors[0], (*it)->predecesors[1]);*/
	}
	int max = 0;
	int temp;
	for(vector<BB>::iterator BBit = CDFG.begin(); BBit != CDFG.end(); BBit++)
	{
		max = 0;
		temp = 0;
		for(list<vertex*>::iterator it= (*BBit).allVertices.begin(); it != (*BBit).allVertices.end(); it++)
		{
			temp = ASAP_BBinit((*BBit), (*it), 1);
			if(temp > max)
				max = temp;
		}
		(*BBit).minLatency = max;
	}
		
	/*for(vector<BB>::iterator BBit = CDFG.begin(); BBit != CDFG.end(); BBit++)
	{
		for(vector<vertex*>::iterator it= (*BBit).allVertices.begin(); it != (*BBit).allVertices.end(); it++)
			printf("%d:\t%d\t%d\t%d\n", (*it)->vertexNum, (*it)->type, (*it)->weight, (*it)->length);
	}*/
	//return 1;
	fclose(file);
	return CDFG;
}

int FDS(list<vertex*> *passedVertices, int passedLatency, S *resourceSet, FILE * schedule, int param)
{
#ifdef FDS_DEBUG
	//fprintf(schedule, "passed Latency %d\n", passedLatency);
#endif
	int tempResourceMatrixUsageOrSomething[NUMBER_OF_RESOURCE_TYPES][200];
	//initialize resource by latency matrix - used to compute the maximum for a given resource for all the time steps
	for(int i = 0; i < NUMBER_OF_RESOURCE_TYPES; i ++)
	{
		for(int j = 1; j <= passedLatency; j++)
			tempResourceMatrixUsageOrSomething[i][j] = 0;
		resourceSet->resCount[i] = 0;
	}
	allVertices = *passedVertices;
	// create a list of all the latencies for each node (1st node has its latency, second has its latency plus the first node, etc)

	configureASAP_ALAP(1, passedLatency);
	
	for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
		if((*it)->timeFrameMax == (*it)->timeFrameMin)
		{
			(*it)->scheduled = 1;
			(*it)->timestep = (*it)->timeFrameMax;
			(*it)->prob = 1;
			//fprintf(schedule, "Vnum %d scheduled %d\n", (*it)->vertexNum, (*it)->timestep);
			//coolFunction((*it), (*it)->timestep);
			updateASAP_ALAP((*it));
		}
	
	int someleft = 0;
	for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
		if((*it)->scheduled == 0)
			someleft = 1;
	int count =0;
	for(int i = 1; i <= LATENCY; i++)
		{
			DGIMULT[i] = 0;
			DGFMULT[i] = 0;
			DGIADD[i] = 0;
			DGFADD[i] = 0;
			DGISUB[i] = 0;
			DGFSUB[i] = 0;
			DGSHIFTR[i] = 0;
			DGSHIFTL[i] = 0;
			DGLOAD[i] = 0;
			DGSTORE[i] = 0;
			DGIDIV[i] = 0;
			DGFDIV[i] = 0;
			DGCMP[i] = 0;
			DGFABS[i] = 0;
			DGFSQR[i] = 0;
			DGIABS[i] = 0;
			DGIAND[i] = 0;

	}
	while(someleft)		//check if there is still something left to be scheduled
	{
		for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
			(*it)->prob = 1/(((float)(*it)->timeFrameMax-(float)(*it)->timeFrameMin)+1);
		someleft = 0;
		/*************************************/
		/*Create the DG for each operation*/
		//initialize DGs to 0 for correct printing - ease of use with arrays so making a bigger array than necessary but using a passed parameter otherwise
		calcDG(passedLatency);  
		//printDG();
		/*************************************/
		/*Calculate the Total Force for each operation in all of its control steps*/
			for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
			{
				if((*it)->scheduled == 0)
				{
					//i is the control step
					for(int i = (*it)->timeFrameMin; i <= (*it)->timeFrameMax; i++)
					{
						float TF = 0;
						float SF = 0;
						float PSF = 0;
						/*self force*/
						//j is the inner control step counting 
						for(int j = (*it)->timeFrameMin; j <= (*it)->timeFrameMax; j++)
						{
							int prob = (j==i)?1:0;
							switch ((*it)->type) 
							{
								case IADD_TYPE: 
									/*Self Force*/
									SF += DGIADD[j] * (prob - (*it)->prob);
									break;
								case FADD_TYPE: 
									SF += DGFADD[j] * (prob - (*it)->prob);
									break;
								case IMULT_TYPE: 
									SF += DGIMULT[j] * (prob - (*it)->prob);
									break;
								case FMULT_TYPE: 
									SF += DGFMULT[j] * (prob - (*it)->prob);
									break;
								case ISUB_TYPE: 
									SF += DGISUB[j] * (prob - (*it)->prob);
									break;
								case FSUB_TYPE: 
									SF += DGFSUB[j] * (prob - (*it)->prob);
									break;
								case RIGHT_SHIFT_TYPE: 
									SF += DGSHIFTR[j] * (prob - (*it)->prob);
									break;
								case LEFT_SHIFT_TYPE:
									SF += DGSHIFTL[j] * (prob - (*it)->prob);
									break;
								case LOAD_TYPE: 
									SF += DGLOAD[j] * (prob - (*it)->prob);
									break;
								case STORE_TYPE: 
									SF += DGSTORE[j] * (prob - (*it)->prob);
									break;
								case IDIV_TYPE:
									SF += DGIDIV[j] * (prob - (*it)->prob);
									break;
								case FDIV_TYPE:
									SF += DGFDIV[j] * (prob - (*it)->prob);
									break;
								case CMP_TYPE:
									SF += DGCMP[j] * (prob - (*it)->prob);
									break;
								case FABS_TYPE:
									SF += DGFABS[j] * (prob - (*it)->prob);
									break;
								case FSQR_TYPE:
									SF += DGFSQR[j] * (prob - (*it)->prob);
									break;
								case IABS_TYPE:
									SF += DGIABS[j] * (prob - (*it)->prob);
									break;
								case IAND_TYPE:
									SF += DGIAND[j] * (prob - (*it)->prob);
									break;
							}
						}
						PSF = SPF(SF, (*it), i);
						TF = SF + PSF;
						//if(totalForce.find(TF)==totalForce.end())
						{
							//ie vertex num at time slot 1 has .25 TF
							//so totalForce[.25] = 1001;
							totalForce[TF] = (*it)->vertexNum*10000 + i;
						}
						//fprintf(schedule, "Vertex#: %d (%d) TF: %.3f, SF: %.3f, PSF: %.3f\n", (*it)->vertexNum, i, TF, SF, PSF);
					}//for
				}//if
			}//for
		/******************************************************/
		/*Choose the operation and control step combo with lowest TF*/
			list<float> sortedTF;
			for(map<float, int>::iterator it = totalForce.begin(); it != totalForce.end(); it++)
				sortedTF.push_front((*it).first);
			sortedTF.sort();
			int sizes = (int)sortedTF.size();
			//if(passedLatency != 5)fprintf(schedule, "1, %d\n", sortedTF.size());
			int combo = totalForce[sortedTF.front()];
			//if(passedLatency != 5)fprintf(schedule, "2\n");
			int vertexNum = combo/10000;
			int controlStep = combo % 10000;
			for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
			{
				if((*it)->vertexNum == vertexNum)
				{
					(*it)->scheduled = 1;
					(*it)->timestep = controlStep;
					(*it)->timeFrameMax = controlStep;
					(*it)->timeFrameMin = controlStep;
					(*it)->prob = 1;
					//fprintf(schedule, "Vnum %d scheduled %d\n", (*it)->vertexNum, (*it)->timestep);
					//coolFunction((*it), controlStep);
					updateASAP_ALAP((*it));
					// after update one node and it's pred and succ vertexes, need to check if this makes any of it's pred
					//  or succ nodes only able to go in one time step and thus have to be scheduled. Then if schedule one of
					//	it's succ's or preds, need to keep going through and updating until nothing has been scheduled and 
					//	there is nothing with only 1 timestep
					int finished = 0;
					int scheduled = 0;
					while(!finished) 
					{
						for(list<vertex*>::iterator it1 = allVertices.begin(); it1 != allVertices.end(); it1++)
						{
							if((*it1)->timeFrameMax == (*it1)->timeFrameMin && !(*it1)->scheduled)
							{
								(*it1)->scheduled = 1;
								(*it1)->timestep = (*it1)->timeFrameMax;
								(*it1)->prob = 1;
								scheduled = 1;
								//fprintf(schedule, "Vnum %d scheduled %d\n", (*it1)->vertexNum, (*it1)->timestep);
								//coolFunction((*it1), (*it1)->timestep);
								updateASAP_ALAP((*it1));
							}
						}
						if (!scheduled)
							finished = 1;
						scheduled = 0;
					}
				}
			}
			totalForce.clear();
			sortedTF.clear();
		/*****************************************************/
		for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
			if((*it)->scheduled == 0)
			{
				someleft = 1;
				break;
			}
	}
	//fprintf(schedule, "\n\n--------------------------\n");
	for(int i = 1; i <= passedLatency; i++)
	{
		fprintf(schedule, "Control Step %d\t\t", globalCount++);
		for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
		{
			//fprintf(schedule, "%d, \n", tempResourceMatrixUsageOrSomething[(*it)->type][i]);
			if((*it)->timestep == i)
			{
				tempResourceMatrixUsageOrSomething[(*it)->type][i]++;
				#ifdef FDS_DEBUG
				fprintf(schedule, "V%d", (*it)->vertexNum);
				switch ((*it)->type) 
				{
					case IADD_TYPE: 
					case FADD_TYPE:
						fprintf(schedule, "+,\t");	
						break;
					case IMULT_TYPE: 
					case FMULT_TYPE: 
						fprintf(schedule, "*,\t");
						break;
					case ISUB_TYPE: 
					case FSUB_TYPE: 
						fprintf(schedule, "-,\t");
						break;
					case RIGHT_SHIFT_TYPE: 
						fprintf(schedule, ">>,\t");
						break;
					case LEFT_SHIFT_TYPE:
						fprintf(schedule, "<<,\t");
						break;
					case LOAD_TYPE: 
						fprintf(schedule, "\\/,\t");
						break;
					case STORE_TYPE:
						fprintf(schedule, "/\\,\t");
						break;
					case IDIV_TYPE:
					case FDIV_TYPE:
						fprintf(schedule, "/\t");
						break;
					case IABS_TYPE:
					case FABS_TYPE:
						fprintf(schedule, "abs,\t");
						break;
					case CMP_TYPE:
						fprintf(schedule, "<>,\t");
						break;
					case FSQR_TYPE:
						fprintf(schedule, "SQR,\t");
						break;
					case IAND_TYPE:
						fprintf(schedule, "&,\t");
						break;
					default:
						fprintf(schedule, "NOTYPE\t");
				}
				#endif
			}
		}
		#ifdef FDS_DEBUG
		fprintf(schedule, "\n");
		#endif
	}
	for(int i = 0; i < NUMBER_OF_RESOURCE_TYPES; i++)
	{
		int max = 0;
		for(int j = 1; j <= passedLatency; j++)
			if(tempResourceMatrixUsageOrSomething[i][j] > max)
			{
				max = tempResourceMatrixUsageOrSomething[i][j];
			}
		resourceSet->resCount[i] = max;
	}
	//printVertices();
	#ifdef FDS_DEBUG
	for(int i = 0; i < NUMBER_OF_RESOURCE_TYPES; i++)
	{
		if(schedule == stdout)
			fprintf(schedule, "%d, ", resourceSet->resCount[i]);
	}
	if(schedule != stdout)	
		fprintf(schedule, "---------------------------\n");
	fprintf(schedule, "\n");
	#endif
	if(param)
	resetAV();
	return 1;
}

void printVertices()
{
	for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
		fprintf(schedule, "%d %d %d %d %d %d %d %d %d %d %d %d %d %f\n", (*it)->vertexNum, (*it)->predecesors[0], (*it)->predecesors[1], (*it)->sucessors[0], (*it)->sucessors[1], (*it)->scheduled, (*it)->type, (*it)->weight, (*it)->length, (*it)->ready, (*it)->timestep, (*it)->timeFrameMin, (*it)->timeFrameMax, (*it)->prob);
}

void printDG()
{
	fprintf(schedule, "DGMULT\n");
	for(int i = 1; i <= 18; i++)
	{
		fprintf(schedule, "%f, ", DGIMULT[i]);
	}
	fprintf(schedule, "\n");
/*	fprintf(schedule, "DGADD:\n");
	for(int i = 1; i <= 10; i++)
	{
		fprintf(schedule, "%f, ", DGIADD[i]);
	}
	fprintf(schedule, "\n");
*/
}

float SPF(float SF, vertex * it , int i)
{
	
	//if my predicessor has a time frame that over laps mine...add it in	
	float PSF = 0;
	int pred1 = it->predecesors[0];
	int pred2 = it->predecesors[1];
	int succ1 = it->sucessors[0];
	int succ2 = it->sucessors[1];
	vertex *tempVertex;
	if(pred1 != -1)
	{
		for(list<vertex *>::iterator avit = allVertices.begin(); avit!=allVertices.end(); avit++)
		{
			if(pred1 == (*avit)->vertexNum)
			{
				tempVertex = (*avit);
				break;
			}
		}
		if(tempVertex->timeFrameMin <= i && tempVertex->timeFrameMax >= i && (!tempVertex->scheduled))
		{
			//start from my min to my max and consider every possibility
			for(int k = tempVertex->timeFrameMin; k <= i-1; k++)
			{
				//If K (control step) is within the time frame of pred1 there will be some force applied
				if(k >= tempVertex->timeFrameMin && k <= tempVertex->timeFrameMax)
				{
					for(int l = tempVertex->timeFrameMin; l <= tempVertex->timeFrameMax; l++)
					{
						int prob = (k==l)?1:0;
						switch (tempVertex->type) 
						{
							case IADD_TYPE: 
								PSF += DGIADD[l] * (prob - (tempVertex->prob));
								break;
							case FADD_TYPE: 
								PSF += DGFADD[l] * (prob - (tempVertex->prob));
								break;
							case IMULT_TYPE: 
								PSF += DGIMULT[l] * (prob - (tempVertex->prob));
								break;
							case FMULT_TYPE: 
								PSF += DGFMULT[l] * (prob - (tempVertex->prob));
								break;
							case ISUB_TYPE: 
								PSF += DGISUB[l] * (prob - (tempVertex->prob));
								break;
							case FSUB_TYPE: 
								PSF += DGFSUB[l] * (prob - (tempVertex->prob));
								break;
							case RIGHT_SHIFT_TYPE: 
								PSF += DGSHIFTR[l] * (prob - (tempVertex->prob));
								break;
							case LEFT_SHIFT_TYPE:
								PSF += DGSHIFTL[l] * (prob - (tempVertex->prob));
								break;
							case LOAD_TYPE: 
								PSF += DGLOAD[l] * (prob - (tempVertex->prob));
								break;
							case STORE_TYPE: 
								PSF += DGSTORE[l] * (prob - (tempVertex->prob));
								break;
							case IDIV_TYPE:
								PSF += DGIDIV[l] * (prob - tempVertex->prob);
								break;
							case FDIV_TYPE:
								PSF += DGFDIV[l] * (prob - tempVertex->prob);
								break;
							case CMP_TYPE:
								PSF += DGCMP[l] * (prob - tempVertex->prob);
								break;
							case FABS_TYPE:
								PSF += DGFABS[l] * (prob - tempVertex->prob);
								break;
							case FSQR_TYPE:
								PSF += DGFSQR[l] * (prob - tempVertex->prob);
								break;
							case IABS_TYPE:
								PSF += DGIABS[l] * (prob - tempVertex->prob);
								break;
							case IAND_TYPE:
								PSF += DGIAND[l] * (prob - tempVertex->prob);
								break;
						}
					}
				}
			}
		}
	}
	if(pred2 != -1)
	{
		for(list<vertex *>::iterator avit = allVertices.begin(); avit!=allVertices.end(); avit++)
		{
			if(pred2 == (*avit)->vertexNum)
			{
				tempVertex = (*avit);
				break;
			}
		}
		if(tempVertex->timeFrameMin <= i && tempVertex->timeFrameMax >= i && (!tempVertex->scheduled))
		{
			int index = (tempVertex->scheduled == 1)?i+1:i;
			//start from my min to my max and consider every possibility
			for(int k = tempVertex->timeFrameMin; k <= i-1; k++)
			{
				//If K (control step) is within the time frame of pred1 there will be some force applied
				if(k >= tempVertex->timeFrameMin && k <= tempVertex->timeFrameMax)
				{
					for(int l = tempVertex->timeFrameMin ; l <= tempVertex->timeFrameMax; l++)
					{
						int prob = (k==l)?1:0;
						switch (tempVertex->type) 
						{
							case IADD_TYPE: 
								PSF += DGIADD[l] * (prob - (tempVertex->prob));
								break;
							case FADD_TYPE: 
								PSF += DGFADD[l] * (prob - (tempVertex->prob));
								break;
							case IMULT_TYPE: 
								PSF += DGIMULT[l] * (prob - (tempVertex->prob));
								break;
							case FMULT_TYPE: 
								PSF += DGFMULT[l] * (prob - (tempVertex->prob));
								break;
							case ISUB_TYPE: 
								PSF += DGISUB[l] * (prob - (tempVertex->prob));
								break;
							case FSUB_TYPE: 
								PSF += DGFSUB[l] * (prob - (tempVertex->prob));
								break;
							case RIGHT_SHIFT_TYPE: 
								PSF += DGSHIFTR[l] * (prob - (tempVertex->prob));
								break;
							case LEFT_SHIFT_TYPE:
								PSF += DGSHIFTL[l] * (prob - (tempVertex->prob));
								break;
							case LOAD_TYPE: 
								PSF += DGLOAD[l] * (prob - (tempVertex->prob));
								break;
							case STORE_TYPE: 
								PSF += DGSTORE[l] * (prob - (tempVertex->prob));
								break;
							case IDIV_TYPE:
								PSF += DGIDIV[l] * (prob - tempVertex->prob);
								break;
							case FDIV_TYPE:
								PSF += DGFDIV[l] * (prob - tempVertex->prob);
								break;
							case CMP_TYPE:
								PSF += DGCMP[l] * (prob - tempVertex->prob);
								break;
							case FABS_TYPE:
								PSF += DGFABS[l] * (prob - tempVertex->prob);
								break;
							case FSQR_TYPE:
								PSF += DGFSQR[l] * (prob - tempVertex->prob);
								break;
							case IABS_TYPE:
								PSF += DGIABS[l] * (prob - tempVertex->prob);
								break;
							case IAND_TYPE:
								PSF += DGIAND[l] * (prob - tempVertex->prob);
								break;
						}
					}
				}
			}
		}
	}
	if(succ1 != -1)
	{
		for(list<vertex *>::iterator avit = allVertices.begin(); avit!=allVertices.end(); avit++)
		{
			if(succ1 == (*avit)->vertexNum)
			{
				tempVertex = (*avit);
				break;
			}
		}
		if(tempVertex->timeFrameMin <= i && tempVertex->timeFrameMax >= i && (!tempVertex->scheduled))
		{
			//start from my min to my max and consider every possibility
			for(int k = i+1; k <= tempVertex->timeFrameMax; k++)
			{
				//If K (control step) is within the time frame of pred1 there will be some force applied
				if(k >= tempVertex->timeFrameMin && k <= tempVertex->timeFrameMax)
				{
					for(int l = tempVertex->timeFrameMin ; l <= tempVertex->timeFrameMax; l++)
					{
						int prob = (k==l)?1:0;
						switch (tempVertex->type) 
						{
							case IADD_TYPE: 
								PSF += DGIADD[l] * (prob - (tempVertex->prob));
								break;
							case FADD_TYPE: 
								PSF += DGFADD[l] * (prob - (tempVertex->prob));
								break;
							case IMULT_TYPE: 
								PSF += DGIMULT[l] * (prob - (tempVertex->prob));
								break;
							case FMULT_TYPE: 
								PSF += DGFMULT[l] * (prob - (tempVertex->prob));
								break;
							case ISUB_TYPE: 
								PSF += DGISUB[l] * (prob - (tempVertex->prob));
								break;
							case FSUB_TYPE: 
								PSF += DGFSUB[l] * (prob - (tempVertex->prob));
								break;
							case RIGHT_SHIFT_TYPE: 
								PSF += DGSHIFTR[l] * (prob - (tempVertex->prob));
								break;
							case LEFT_SHIFT_TYPE:
								PSF += DGSHIFTL[l] * (prob - (tempVertex->prob));
								break;
							case LOAD_TYPE: 
								PSF += DGLOAD[l] * (prob - (tempVertex->prob));
								break;
							case STORE_TYPE: 
								PSF += DGSTORE[l] * (prob - (tempVertex->prob));
								break;
							case IDIV_TYPE:
								PSF += DGIDIV[l] * (prob - tempVertex->prob);
								break;
							case FDIV_TYPE:
								PSF += DGFDIV[l] * (prob - tempVertex->prob);
								break;
							case CMP_TYPE:
								PSF += DGCMP[l] * (prob - tempVertex->prob);
								break;
							case FABS_TYPE:
								PSF += DGFABS[l] * (prob - tempVertex->prob);
								break;
							case FSQR_TYPE:
								PSF += DGFSQR[l] * (prob - tempVertex->prob);
								break;
							case IABS_TYPE:
								PSF += DGIABS[l] * (prob - tempVertex->prob);
								break;
							case IAND_TYPE:
								PSF += DGIAND[l] * (prob - tempVertex->prob);
								break;
						}
					}
				}
			}
		}
	}
	if(succ2 != -1)
	{
		for(list<vertex *>::iterator avit = allVertices.begin(); avit!=allVertices.end(); avit++)
		{
			if(succ2 == (*avit)->vertexNum)
			{
				tempVertex = (*avit);
				break;
			}
		}
		if(tempVertex->timeFrameMin <= i && tempVertex->timeFrameMax >= i && (!tempVertex->scheduled))
		{
			//start from my min to my max and consider every possibility
			//int index = (tempVertex->scheduled == 1)?i-1:i+1;
			for(int k = i+1; k <= tempVertex->timeFrameMax; k++)
			{
				//If K (control step) is within the time frame of pred1 there will be some force applied
				if(k >= tempVertex->timeFrameMin && k <= tempVertex->timeFrameMax)
				{
					for(int l = tempVertex->timeFrameMin ; l <= tempVertex->timeFrameMax; l++)
					{
						int prob = (k==l)?1:0;
						switch (tempVertex->type) 
						{
							case IADD_TYPE: 
								PSF += DGIADD[l] * (prob - (tempVertex->prob));
								break;
							case FADD_TYPE: 
								PSF += DGFADD[l] * (prob - (tempVertex->prob));
								break;
							case IMULT_TYPE: 
								PSF += DGIMULT[l] * (prob - (tempVertex->prob));
								break;
							case FMULT_TYPE: 
								PSF += DGFMULT[l] * (prob - (tempVertex->prob));
								break;
							case ISUB_TYPE: 
								PSF += DGISUB[l] * (prob - (tempVertex->prob));
								break;
							case FSUB_TYPE: 
								PSF += DGFSUB[l] * (prob - (tempVertex->prob));
								break;
							case RIGHT_SHIFT_TYPE: 
								PSF += DGSHIFTR[l] * (prob - (tempVertex->prob));
								break;
							case LEFT_SHIFT_TYPE:
								PSF += DGSHIFTL[l] * (prob - (tempVertex->prob));
								break;
							case LOAD_TYPE: 
								PSF += DGLOAD[l] * (prob - (tempVertex->prob));
								break;
							case STORE_TYPE: 
								PSF += DGSTORE[l] * (prob - (tempVertex->prob));
								break;
							case IDIV_TYPE:
								PSF += DGIDIV[l] * (prob - tempVertex->prob);
								break;
							case FDIV_TYPE:
								PSF += DGFDIV[l] * (prob - tempVertex->prob);
								break;
							case CMP_TYPE:
								PSF += DGCMP[l] * (prob - tempVertex->prob);
								break;
							case FABS_TYPE:
								PSF += DGFABS[l] * (prob - tempVertex->prob);
								break;
							case FSQR_TYPE:
								PSF += DGFSQR[l] * (prob - tempVertex->prob);
								break;
							case IABS_TYPE:
								PSF += DGIABS[l] * (prob - tempVertex->prob);
								break;
							case IAND_TYPE:
								PSF += DGIAND[l] * (prob - tempVertex->prob);
								break;
						}
					}
				}
			}
		}
	}
	return PSF;
}

int ASAPinit(vertex *node, int latency)
{
	if(node->predecesors[0] == -1 && node->predecesors[1] == -1)
	{
		node->timeFrameMin = 1;
		return 1;
	}
	int min = 0;
	for(list<vertex*>::iterator it2= allVertices.begin(); it2 != allVertices.end(); it2++)
	{
		int num = node->vertexNum;
		if((*it2)->vertexNum == node->predecesors[1] || (*it2)->vertexNum == node->predecesors[0])
		{
			int temp = 1 + ASAPinit((*it2), latency);
			if(temp > min)
				min = temp;
		}
	}
	node->timeFrameMin = min;
	return min;
}

int ASAP_BBinit(BB bb1, vertex *node, int latency)
{
	if(node->predecesors[0] == -1 && node->predecesors[1] == -1)
	{
		node->timeFrameMin = 1;
		return 1;
	}
	int min = 0;
	for(list<vertex*>::iterator it2= bb1.allVertices.begin(); it2 != bb1.allVertices.end(); it2++)
	{
		if((*it2)->vertexNum == node->predecesors[1] || (*it2)->vertexNum == node->predecesors[0])
		{
			int temp = 1 + ASAP_BBinit(bb1, (*it2), latency);
			if(temp > min)
				min = temp;
		}
	}
	node->timeFrameMin = min;
	return min;
}

int ALAPinit(vertex *node, int latency)
{
	if(node->sucessors[0] == -1 && node->sucessors[1] == -1)
	{
		node->timeFrameMax = latency;
		return latency;
	}
	int max = latency;
	for(list<vertex*>::iterator it2= allVertices.begin(); it2 != allVertices.end(); it2++)
	{
		if((*it2)->vertexNum == node->sucessors[0] || (*it2)->vertexNum == node->sucessors[1])
		{
			int temp;
			temp = ALAPinit((*it2), latency)- 1;
			if(temp < max)
				max = temp;
		}

	}
	node->timeFrameMax = max;
	return max;
}

void configureASAP_ALAP(int min, int latency)
{
	for(list<vertex*>::iterator it= allVertices.begin(); it != allVertices.end(); it++)
	{
		ASAPinit((*it), min);
		ALAPinit((*it), latency);
	}
}

void updateASAP_ALAP(vertex * me)
{
	ASAP(me, me->timestep+1);
	ALAP(me, me->timestep-1);
	for(list<vertex*>::iterator it= allVertices.begin(); it != allVertices.end(); it++)
	{
		if((*it)->timeFrameMax == (*it)->timeFrameMin && !(*it)->scheduled)
		{
			(*it)->scheduled = 1;
			(*it)->timestep = (*it)->timeFrameMax;
			(*it)->prob = 1;
			//fprintf(schedule, "Vnum %d scheduled (ALAP ASAP)%d\n", (*it)->vertexNum, (*it)->timestep);
			updateASAP_ALAP((*it));
		}
	}
}

void ASAP(vertex *node, int latency)
{
	if(node->sucessors[0] == -1 && node->sucessors[1] == -1)
		return;
	if(node->sucessors[0] != -1)
		for(list<vertex*>::iterator it2= allVertices.begin(); it2 != allVertices.end(); it2++)
			if(node->sucessors[0] == (*it2)->vertexNum && !(*it2)->scheduled)
			{
				if (latency > (*it2)->timeFrameMin)
					(*it2)->timeFrameMin = latency;
				ASAP((*it2), (*it2)->timeFrameMin+1);
			}
	if(node->sucessors[1] != -1)
		for(list<vertex*>::iterator it2= allVertices.begin(); it2 != allVertices.end(); it2++)
			if(node->sucessors[1] == (*it2)->vertexNum && !(*it2)->scheduled)
			{
				if (latency > (*it2)->timeFrameMin)
					(*it2)->timeFrameMin = latency;
				ASAP((*it2), (*it2)->timeFrameMin+1);
			}
}

void ALAP(vertex *node, int latency)
{
	if(node->predecesors[0] == -1 && node->predecesors[1] == -1)
		return;
	if(node->predecesors[0] != -1)
		for(list<vertex*>::iterator it2= allVertices.begin(); it2 != allVertices.end(); it2++)
			if(node->predecesors[0] == (*it2)->vertexNum && !(*it2)->scheduled)
			{
				(*it2)->timeFrameMax = latency;
				ALAP((*it2), latency-1);
			}
	if(node->predecesors[1] != -1)
		for(list<vertex*>::iterator it2= allVertices.begin(); it2 != allVertices.end(); it2++)
			if(node->predecesors[1] == (*it2)->vertexNum && !(*it2)->scheduled)
			{
				(*it2)->timeFrameMax = latency;
				ALAP((*it2), latency-1);
			}
}

void calcDG(int passedLatency)
{
	for(int i = 1; i <= passedLatency; i++)
	{
		float probs[NUMBER_OF_RESOURCE_TYPES];
		for(int j = 0; j < NUMBER_OF_RESOURCE_TYPES; j++)
			probs[j] = 0;

		for(list<vertex*>::iterator it = allVertices.begin(); it != allVertices.end(); it++)
			if ((*it)->timeFrameMin <= i && (*it)->timeFrameMax >= i) 
				probs[(*it)->type] += (*it)->prob;

		DGIMULT[i] 	= probs[IMULT_TYPE];
		DGFMULT[i] 	= probs[FMULT_TYPE];
		DGIADD[i] 	= probs[IADD_TYPE];
		DGFADD[i] 	= probs[FADD_TYPE];
		DGISUB[i] 	= probs[ISUB_TYPE];
		DGFSUB[i] 	= probs[FSUB_TYPE];
		DGSHIFTR[i] = probs[RIGHT_SHIFT_TYPE];
		DGSHIFTL[i] = probs[LEFT_SHIFT_TYPE];
		DGLOAD[i] 	= probs[LOAD_TYPE];
		DGSTORE[i] 	= probs[STORE_TYPE];
		DGIDIV[i] 	= probs[IDIV_TYPE];
		DGFDIV[i] 	= probs[FDIV_TYPE];
		DGCMP[i] 	= probs[CMP_TYPE];
		DGFABS[i] 	= probs[FABS_TYPE];
		DGFSQR[i] 	= probs[FSQR_TYPE];	
		DGIABS[i]	= probs[IABS_TYPE];
		DGIAND[i]	= probs[IAND_TYPE];
	} 
}